/*

 * Copyright (c) 2014, Oracle America, Inc.

 * All rights reserved.

 *

 * Redistribution and use in source and binary forms, with or without

 * modification, are permitted provided that the following conditions are met:

 *

 *  * Redistributions of source code must retain the above copyright notice,

 *    this list of conditions and the following disclaimer.

 *

 *  * Redistributions in binary form must reproduce the above copyright

 *    notice, this list of conditions and the following disclaimer in the

 *    documentation and/or other materials provided with the distribution.

 *

 *  * Neither the name of Oracle nor the names of its contributors may be used

 *    to endorse or promote products derived from this software without

 *    specific prior written permission.

 *

 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"

 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE

 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE

 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE

 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR

 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF

 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS

 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN

 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)

 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF

 * THE POSSIBILITY OF SUCH DAMAGE.

 */

package org.openjdk.jmh.samples;


import org.openjdk.jmh.annotations.Benchmark;

import org.openjdk.jmh.annotations.OutputTimeUnit;

import org.openjdk.jmh.annotations.Scope;

import org.openjdk.jmh.annotations.State;

import org.openjdk.jmh.runner.Runner;

import org.openjdk.jmh.runner.RunnerException;

import org.openjdk.jmh.runner.options.Options;

import org.openjdk.jmh.runner.options.OptionsBuilder;

import org.openjdk.jmh.runner.options.TimeValue;


import java.util.concurrent.TimeUnit;


@State(Scope.Thread)

@OutputTimeUnit(TimeUnit.MILLISECONDS)

public class JMHSample_17_SyncIterations {


 /*

  * This is the another thing that is enabled in JMH by default.

  *

  * Suppose we have this simple benchmark.

  */


 private double src;


 @Benchmark

 public double test() {

  double s = src;

  for (int i = 0; i < 1000; i++) {

   s = Math.sin(s);

  }

  return s;

 }


 /*

  * It turns out if you run the benchmark with multiple threads,

  * the way you start and stop the worker threads seriously affects

  * performance.

  *

  * The natural way would be to park all the threads on some sort

  * of barrier, and the let them go "at once". However, that does

  * not work: there are no guarantees the worker threads will start

  * at the same time, meaning other worker threads are working

  * in better conditions, skewing the result.

  *

  * The better solution would be to introduce bogus iterations,

  * ramp up the threads executing the iterations, and then atomically

  * shift the system to measuring stuff. The same thing can be done

  * during the rampdown. This sounds complicated, but JMH already

  * handles that for you.

  *


  */


 /*

  * ============================== HOW TO RUN THIS TEST: ====================================

  *

  * You will need to oversubscribe the system to make this effect

  * clearly visible; however, this effect can also be shown on the

  * unsaturated systems.*

  *

  * Note the performance of -si false version is more flaky, even

  * though it is "better". This is the false improvement, granted by

  * some of the threads executing in solo. The -si true version more stable

  * and coherent.

  *

  * -si true is enabled by default.

  *

  * Say, $CPU is the number of CPUs on your machine.

  *

  * You can run this test with:

  *

  * a) Via the command line:

  *    $ mvn clean install

  *    $ java -jar target/benchmarks.jar JMHSample_17 \

  *        -w 1s -r 1s -f 1 -t ${CPU*16} -si {true|false}

  *    (we requested shorter warmup/measurement iterations, single fork,

  *     lots of threads, and changeable "synchronize iterations" option)

  *

  * b) Via the Java API:

  *    (see the JMH homepage for possible caveats when running from IDE:

  *      http://openjdk.java.net/projects/code-tools/jmh/)

  */


 public static void main(String[] args) throws RunnerException {

  Options opt = new OptionsBuilder()

          .include(JMHSample_17_SyncIterations.class.getSimpleName())

          .warmupTime(TimeValue.seconds(1))

          .measurementTime(TimeValue.seconds(1))

          .threads(Runtime.getRuntime().availableProcessors()*16)

          .forks(1)

          .syncIterations(true) // try to switch to "false"

          .build();


  new Runner(opt).run();

 }
// 本例阐述了在多线程条件下，线程池的启动与销毁都会影响基准测试的准确性，如果自己来实现需要让线程同时开始启动工作，但这又比较难做到，如果在启动和关闭线程池时，无法做到同时，那么测量必定不准确，因为无法确定开始和结束时间；JMH提供了多线程基准测试的方法，先让线程池预热，都预热完成后让所有线程同时进行基准测试，测试完等待所有线程都结束再关闭线程池。
// 这里warmupTime是预热时间，measurementTime是测量时间，threads是线程数，forks之前说过，是fork出一个子进程进行测试，syncIterations是是否需要同步预热，前面几个参数好理解，看了下代码才知道syncIterations如果设置为true代表等所有线程预热完成，然后所有线程一起进入测量阶段，等所有线程执行完测试后，再一起进入关闭；看一下设置为false时跑出的结果：
//
// Benchmark       Mode  Cnt    Score    Error   Units
// Sample17.test  thrpt    5  189.855 ± 23.415  ops/ms
//
// 再看一下为true的结果：
//
// Benchmark       Mode  Cnt    Score    Error   Units
// Sample17.test  thrpt    5  173.435 ± 41.659  ops/ms
//
// 当syncIterations设置为true时更准确地反应了多线程下被测试方法的性能，这个参数默认为true，无需手动设置。

}